/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __PQ_TerrainManager_H__
#define __PQ_TerrainManager_H__

#include "EnginePrerequisites.h"

#include "OgrePageManager.h"

#include "TerrainObject.h"
#include "TerrainGroupObject.h"

namespace PQEngine
{
	/*Each scene object have a terrain manager.
	Used to create and modify terrain in OGRE.
	*/
	class TerrainManager
	{
	public:
		static const int TERRAIN_PAGE_MIN_X= 0;
		static const int TERRAIN_PAGE_MIN_Y= 0;
		static const int TERRAIN_PAGE_MAX_X= 0;
		static const int TERRAIN_PAGE_MAX_Y= 0;
		static const int TERRAIN_SLOT_MAX= 32768;
		static const int TERRAIN_SIZE=513;
		static const int TERRAIN_SCALE=24;
		static const int TERRAIN_WORLD_SIZE=(TERRAIN_SIZE-1)*TERRAIN_SCALE;
		static const int BRUSH_DATA_SIZE=128;
		static const float TERRAIN_DEFAULT_RESTITUTION;
		static const float TERRAIN_DEFAULT_FRICTION;
		static const std::string TERRAIN_FILE_PREFIX;
		static const std::string TERRAIN_FILE_SUFFIX;
		

	public:
		TerrainManager(SceneObject *sceneObject);
		~TerrainManager();
		
		/*Add terrain layer to current selected terrain object with named texture image.
		@param textureName  Simple texture name with extension(eg. desert.png)(not path).
		*/
		void addTerrainLayer(std::string textureName);

		/*Add terrain layer to terrain object with named texture image.
		@param terrainObject Terrain object that need to add layer to it.
		@param textureName  Simple texture name with extension(eg. desert.png)(not path).
		*/
		void addTerrainLayer(TerrainObject* terrainObject,std::string textureName);

		/*Add terrain layer with texture image index in terrain texture archive.
		@param terrainObject Terrain object that need to add layer to it.
		@param textureIndex  Texture image index in terrain texture archive.
		*/
		void addTerrainLayer(TerrainObject* terrainObject,int textureIndex);

		/*Add terrain layer with texture image index in terrain texture archive.
		@param textureIndex  Texture image index in terrain texture archive.
		*/
		void addTerrainLayer(int textureIndex);

		StringVector getTextureLayerName();
		

		inline void selectLayer(int index)
		{
			if(_selectedTerrain){
				_selectedTerrain->selectLayer(index);
			}
		}

		inline void deselectTerrain()
		{
			_selectedTerrain=0;
		}

		inline int getSelectedLayer()
		{
			if(_selectedTerrain){
				return _selectedTerrain->getSelectedLayer();
			}else{
				return -1;
			}
		}

		void update(float deltaT);

		void initTerrainGroup();

		/*Get the terrain group object.
		@Note Each scene can only have one such group.
		*/
		TerrainGroupObject* getTerrainGroup();
		
		/*Create a flat terrain chunk in position slotX slotY with diffuse texture index in terrain texture GPK archive.
		@param slotX The X coord of slot position.
		@param slotX The Y coord of slot position.
		@param diffuseTexIndex The diffuse texture index in terrain texture GPK archive.
		*/
		TerrainObject* createFlatTerrain(int slotX,int slotY,int diffuseTexIndex);

		TerrainObject* getTerrain(int mouseX,int mouseY);

		/*Select terrain object by curent viewport screen mouse position
		*/
		TerrainObject* selectTerrain(int mouseX,int mouseY);
		TerrainObject* selectTerrain(int id);
		TerrainObject* getSelectedTerrain(){ return _selectedTerrain; }

		
	private:
		void initTerrainGlobalOptions();
		void initTerrainDecal();
		TerrainObject* selectTerrain(Ogre::Terrain* terrain);
	private:
		SceneObject* _sceneObject;//owner
		
		Ogre::SceneManager *_sceneMgr;	
		Ogre::Light* _light;//terrain light
		Ogre::TerrainGlobalOptions* _terrainGlobalOptions;
		Ogre::TerrainGroup* _terrainGroup;
		Ogre::TerrainPaging* _terrainPaging;
		Ogre::PageManager* _pageManager;
		Ogre::PagedWorld* _pagedWorld;
		Ogre::Vector3 _position;//origin position
		bool _paging;
		bool _terrainsImported;
		float _brushSize;//BrushSize in TerrainSpace

		
		TerrainGroupObject* _terrainGroupObject;
		TerrainObject* _selectedTerrain;//current selected terrain object.
		
		Ogre::Frustum* _decalFrustum;
		Ogre::SceneNode* _decalNode;

		bool _isEditing;

	public:
		void OnMouseMove(int x,int y);
	private:
		int _mouseX;
		int _mouseY;

	protected:
		/// This class just pretends to provide prcedural page content to avoid page loading
		class DummyPageProvider : public Ogre::PageProvider
		{
		public:
			bool prepareProceduralPage(Ogre::Page* page, Ogre::PagedWorldSection* section) { return true; }
			bool loadProceduralPage(Ogre::Page* page, Ogre::PagedWorldSection* section) { return true; }
			bool unloadProceduralPage(Ogre::Page* page, Ogre::PagedWorldSection* section) { return true; }
			bool unprepareProceduralPage(Ogre::Page* page, Ogre::PagedWorldSection* section) { return true; }
		};
		DummyPageProvider __pageProvider;//two underscore mean protected member,one underscore mean private
	};
}

#endif
